//------------------------------------------------------------------------------
//
// classname: DebugReport
// version: 0.1.3
// author: 小兵( aosnow@yeah.net )
// created: 2013-1-9
//
// 调试信息输出器
// Copyright (c) 2012 小兵( aosnow@yeah.net )
//
//------------------------------------------------------------------------------

package
{
	import flash.display.DisplayObjectContainer;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;

	public class Debug extends Sprite
	{
		//--------------------------------------------------------------------------
		//
		//  Class constructor
		//
		//--------------------------------------------------------------------------

		public static var current:Debug;

		public function Debug()
		{
			if( current )
			{
				throw new Error( "Debuger is created!" );
			}

			if( current == null )
			{
				current = this;
				addEventListener( Event.ADDED_TO_STAGE, addedToStageHandler );
			}
		}

		//--------------------------------------------------------------------------
		//
		//	Class properties
		//
		//--------------------------------------------------------------------------

		private var _inited:Boolean;

		private var _bgRect:Shape;
		private var _scrollbar:SfScrollBar;
		private var _displayText:TextField;
		private var _padding:Number = 10;
		private var _btnSwitch:SButton;
		private var _btnClean:SButton;
		private var _state:String = "open";

		//--------------------------------------------------------------------------
		//
		//	Class methods
		//
		//--------------------------------------------------------------------------

		public static function init( container:DisplayObjectContainer ):void
		{
			if( current == null )
			{
				container.addChild( new Debug());
			}
		}

		protected function destroy():void
		{
			_bgRect.graphics.clear();
			removeChildren();

			_bgRect = null;
			_displayText = null;
			_btnSwitch = null;
			_btnClean = null;
			_bgRect = null;
			_scrollbar = null;

			_inited = false;
		}

		protected function addChildren():void
		{
			if( _inited )
				return;

			_inited = true;

			var drawW:Number = stage ? stage.stageWidth : 900;
			var drawH:Number = stage ? stage.stageHeight : 500;

			_bgRect = new Shape();
//			_bgRect.width = drawW;
//			_bgRect.height = drawH;
			_bgRect.graphics.beginFill( 0xffffff, 0.9 );
			_bgRect.graphics.lineStyle( 2, 0x000000, 0.6 );
			_bgRect.graphics.drawRoundRect( 0, 0, drawW, drawH, 8, 8 );
			_bgRect.graphics.endFill();
			addChild( _bgRect );

			_displayText = new TextField();
			_displayText.x = _padding;
			_displayText.y = _padding + 30;
			_displayText.width = width - _padding * 2 - 15;
			_displayText.height = height - _padding * 2 - 30;
			_displayText.multiline = true;
			_displayText.wordWrap = true;
			_displayText.border = true;
			_displayText.borderColor = 0x80000000;

			var format:TextFormat = new TextFormat( "Courier New", 12, 0 );
			_displayText.defaultTextFormat = format;
			_displayText.setTextFormat( format );
			_displayText.text = "";

			_displayText.addEventListener( Event.SCROLL, scrollHandler );
			addChild( _displayText );

			_btnSwitch = new SButton();
			_btnSwitch.x = _btnSwitch.y = 5;
			_btnSwitch.label = "关闭调试器";
			_btnSwitch.addEventListener( MouseEvent.CLICK, btnClickHandler );
			_btnSwitch.addEventListener( MouseEvent.ROLL_OVER, btnRollHandler );
			_btnSwitch.addEventListener( MouseEvent.ROLL_OUT, btnRollHandler );
			_btnSwitch.alpha = 0.1;
			addChild( _btnSwitch );

			_btnClean = new SButton();
			_btnClean.x = _btnSwitch.x + _btnSwitch.width + 5;
			_btnClean.y = 5;
			_btnClean.label = " 清 空 ";
			_btnClean.addEventListener( MouseEvent.CLICK, btnCleanHandler );
			_btnClean.addEventListener( MouseEvent.ROLL_OVER, btnRollHandler );
			_btnClean.addEventListener( MouseEvent.ROLL_OUT, btnRollHandler );
			_btnClean.alpha = 0.1;
			addChild( _btnClean );

			_scrollbar = new SfScrollBar();
			_scrollbar.width = 15;
			_scrollbar.height = _displayText.height;
			_scrollbar.x = _displayText.x + _displayText.width + 2;
			_scrollbar.y = _displayText.y;
			_scrollbar.addEventListener( "position", scrollbarPositionHandler );
			addChild( _scrollbar );

			close();
		}

		public function open():void
		{
			_state = "open";
			_btnSwitch.label = "关闭调试器";

			_bgRect.visible = true;
			_displayText.visible = true;
			_scrollbar.visible = true;
		}

		public function close():void
		{
			_state = "close";
			_btnSwitch.label = "打开调试器";

			_bgRect.visible = false;
			_displayText.visible = false;
			_scrollbar.visible = false;
		}

		protected function updateScroller():void
		{
			_displayText.scrollV = _displayText.numLines;
			_scrollbar.update( Math.min( _displayText.height / _displayText.textHeight, 1 ));
			_scrollbar.position = 1;
		}

		/**
		 * 追加一些需要显示的调试信息显示到调试输出控制台
		 * @param value
		 */
		public function _append( value:String ):void
		{
			value = ( _displayText.length > 0 ? "\n" : "" ) + value;

			_displayText.appendText( value );
			updateScroller();
		}

		/**
		 * 清空调试信息，并将参数内容显示到调试输出控制台
		 * @param value
		 */
		public function _print( value:String, html:Boolean = false ):void
		{
			if( html )
				_displayText.htmlText = value;
			else
				_displayText.text = value;
			updateScroller();
		}

		/**
		 * 追加一些需要显示的调试信息显示到调试输出控制台
		 * <p>追加输出，只支持纯文本</p>
		 * @param value
		 */
		public static function append( ... values ):void
		{
			if( current )
			{
				var r:String = "";

				for( var i:int = 0, lng:int = values.length; i < lng; i++ )
				{
					r += ( values[ i ] as String ) + "\t";
				}
				current._append( r );
			}
		}

		/**
		 * 清空调试信息，并将参数内容显示到调试输出控制台
		 * @param value
		 */
		public static function print( value:String, html:Boolean = false ):void
		{
			if( current )
				current._print( value, html );
		}

		//--------------------------------------------------------------------------
		//
		//  Event handlers
		//
		//--------------------------------------------------------------------------

		private function addedToStageHandler( event:Event ):void
		{
			removeEventListener( Event.ADDED_TO_STAGE, addedToStageHandler );
			addEventListener( Event.REMOVED_FROM_STAGE, removedToStageHandler );
			addChildren();
		}

		private function removedToStageHandler( event:Event ):void
		{
			removeEventListener( Event.REMOVED_FROM_STAGE, removedToStageHandler );
			destroy();
		}

		private function btnRollHandler( event:MouseEvent ):void
		{
			if( event.type == MouseEvent.ROLL_OVER )
			{
				event.target.alpha = 1;
			}
			else
			{
				event.target.alpha = 0.1;
			}
		}

		private function btnCleanHandler( event:MouseEvent ):void
		{
			_displayText.text = "";
		}

		private function btnClickHandler( event:MouseEvent ):void
		{
			if( _state == "close" )
			{
				open();
			}
			else
			{
				close();
			}
		}

		private function scrollHandler( event:Event ):void
		{
			if( !_scrollbar.isDraging )
				_scrollbar.updatePosition( _displayText.scrollV / _displayText.maxScrollV );
		}

		private function scrollbarPositionHandler( event:Event ):void
		{
			_displayText.scrollV = _scrollbar.position * _displayText.maxScrollV >> 0;
		}
	}
}
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;

import starfire.utils.maths.max;

class SfScrollBar extends Sprite
{

	public function SfScrollBar()
	{
		_bg = new Shape();
		addChild( _bg );

		_bar = new Sprite();
		_bar.buttonMode = true;
		addChild( _bar );

		_dragBounds = new Rectangle();
		_oldY = _bar.y;

		addEventListener( Event.ADDED_TO_STAGE, function( event:Event ):void
		{
			_bar.addEventListener( MouseEvent.MOUSE_DOWN, mouseHandler );
			stage.addEventListener( MouseEvent.MOUSE_UP, mouseHandler );
			stage.addEventListener( MouseEvent.MOUSE_MOVE, mouseHandler );

			update( 1 );
		});

	}

	//--------------------------------------------------------------------------
	//
	//	Class properties
	//
	//--------------------------------------------------------------------------

	private var _bg:Shape;
	private var _bar:Sprite;
	private var _dragBounds:Rectangle;
	private var _oldY:Number;

	//----------------------------------------
	//  isDraging
	//----------------------------------------

	private var _isDraging:Boolean;

	public function get isDraging():Boolean
	{
		return _isDraging;
	}

	//----------------------------------------
	//  width
	//----------------------------------------

	private var _width:Number;

	override public function set width( value:Number ):void
	{
		_width = value;
		update();
	}

	override public function get width():Number
	{
		return _width;
	}

	//----------------------------------------
	//  height
	//----------------------------------------

	private var _height:Number;

	override public function set height( value:Number ):void
	{
		_height = value;
		update();
	}

	override public function get height():Number
	{
		return _height;
	}

	//----------------------------------------
	//  position
	//----------------------------------------

	private var _position:Number = 0;

	public function get position():Number
	{
		return _position;
	}

	public function set position( value:Number ):void
	{
		_position = value;
		updatePosition();
	}

	//--------------------------------------------------------------------------
	//
	//	Class methods
	//
	//--------------------------------------------------------------------------

	public function update( scale:Number = 0.5 ):void
	{
		var bh:Number = Math.max( 30, _height * scale >> 0 );
		_dragBounds.setTo( 0, 0, 0, _height - bh );

		updateBar( scale );
		updateBackgroud();
		updatePosition();

		_oldY = _bar.y;
	}

	public function updatePosition( value:Number = NaN ):void
	{
		var p:Number = isNaN( value ) ? _position : value;
		_bar.y = Math.max( 0, ( _height - _bar.height ) * p >> 0 );
	}

	public function updateBar( scale:Number ):void
	{
		if( !isNaN( _width ) && !isNaN( _height ))
		{
			if( scale >= 1 )
			{
				_bar.graphics.clear();
			}
			else
			{
				var bh:Number = Math.max( 30, _height * scale >> 0 );

				_bar.graphics.clear();
				_bar.graphics.lineStyle( 1, 0xffffff, 0.8 );
				_bar.graphics.beginFill( 0x0, 0.5 );
				_bar.graphics.drawRoundRect( 0, 0, _width, bh, 2, 2 );
				_bar.graphics.endFill();

				_bar.graphics.lineStyle( 1, 0xffffff, 0 );
				_bar.graphics.beginFill( 0xffffff, 0.3 );
				_bar.graphics.drawRoundRect( 0, 0, _width * 0.5 >> 0, bh, 2, 2 );
				_bar.graphics.endFill();
			}
		}
	}

	public function updateBackgroud():void
	{
		if( !isNaN( _width ) && !isNaN( _height ))
		{
			_bg.graphics.clear();
			_bg.graphics.beginFill( 0x000000, 0.2 );
			_bg.graphics.drawRoundRect( 0, 0, _width, _height, 4, 4 );
			_bg.graphics.endFill();
		}
	}

	//--------------------------------------------------------------------------
	//
	//  Event handlers
	//
	//--------------------------------------------------------------------------

	private function mouseHandler( event:MouseEvent ):void
	{
		if( event.type == MouseEvent.MOUSE_DOWN )
		{
			_isDraging = true;
			_bar.alpha = 0.5;
			_bar.startDrag( false, _dragBounds );
		}
		else if( event.type == MouseEvent.MOUSE_MOVE && _isDraging )
		{
			if( _position != _bar.y / ( _height - _bar.height ))
			{
				_position = _bar.y / ( _height - _bar.height );
				dispatchEvent( new Event( "position" ));
			}
			_oldY = _bar.y;
		}
		else
		{
			_isDraging = false;
			_bar.alpha = 1;
			_bar.stopDrag();
		}
	}
}

class SButton extends Sprite
{
	private var _bg:Shape;
	private var _txt:TextField;
	private var _padding:int = 5;

	public function SButton()
	{
		_bg = new Shape();
		addChild( _bg );

		_txt = new TextField();
		_txt.mouseEnabled = false;
		_txt.multiline = false;
		_txt.autoSize = TextFieldAutoSize.LEFT;
		var format:TextFormat = new TextFormat( "Courier New", 12, 0xffffff );
		_txt.defaultTextFormat = format;
		_txt.setTextFormat( format );
		addChild( _txt );

		buttonMode = true;
	}

	private var _label:String;

	public function get label():String
	{
		return _label;
	}

	public function set label( value:String ):void
	{
		if( _label == value )
			return;

		_label = value;
		update();
	}

	protected function update():void
	{
		_txt.text = _label;

		updateBackground( _txt.width + _padding * 4, _txt.height + _padding * 2 );
	}

	protected function updateBackground( width:Number, height:Number ):void
	{
		_bg.graphics.clear();
		_bg.graphics.beginFill( 0x000000, 0.8 );
		_bg.graphics.drawRoundRect( 0, 0, width, height, 8, 8 );
		_bg.graphics.endFill();

		_txt.x = width - _txt.width >> 1;
		_txt.y = height - _txt.height >> 1;
	}
}
